// progtest.cc 
//      Test routines for demonstrating that Nachos can load
//      a user program and execute it.  
//
//      Also, routines for testing the Console hardware device.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"
#include "console.h"
#include "synchconsole.h"
#include "addrspace.h"
#include "synch.h"

//----------------------------------------------------------------------
// StartProcess
//      Run a user program.  Open the executable, load it into
//      memory, and jump to it.
//----------------------------------------------------------------------

void
StartProcess (char *filename)
{
    OpenFile *executable = fileSystem->Open (filename);
    AddrSpace *space;

    if (executable == NULL)
      {
	  printf ("Unable to open file %s\n", filename);
	  return;
      }
    space = new AddrSpace (executable);
    currentThread->space = space;

    #ifdef CHANGED
    machine-> numProcesses++;
    #endif // CHANGED
    
    delete executable;		// close file

    space->InitRegisters ();	// set the initial register values
    space->RestoreState ();	// load page table register

    machine->Run ();		// jump to the user progam
    ASSERT (FALSE);		// machine->Run never returns;
    // the address space exits
    // by doing the syscall "exit"
}

// Data structures needed for the console test.  Threads making
// I/O requests wait on a Semaphore to delay until the I/O completes.

static Console *console;
static Semaphore *readAvail;
static Semaphore *writeDone;

//----------------------------------------------------------------------
// ConsoleInterruptHandlers
//      Wake up the thread that requested the I/O.
//----------------------------------------------------------------------

static void
ReadAvail (void *arg)
{
    (void) arg;
    readAvail->V ();
}
static void
WriteDone (void *arg)
{
    (void) arg;
    writeDone->V ();
}

//----------------------------------------------------------------------
// ConsoleTest
//      Test the console by echoing characters typed at the input onto
//      the output.  Stop when the user types a 'q'.
//----------------------------------------------------------------------

void
ConsoleTest (const char *in, const char *out)
{
    char ch;

    readAvail = new Semaphore ("read avail", 0);
    writeDone = new Semaphore ("write done", 0);
    console = new Console (in, out, ReadAvail, WriteDone, 0);

    for (;;)
      {
	  readAvail->P ();	// wait for character to arrive
	  ch = console->GetChar ();

#ifdef CHANGED
      if (ch != '\n') {
        console->PutChar('<');
        writeDone->P();
        console->PutChar (ch);	// echo it!
        writeDone->P ();	// wait for write to finish
        console->PutChar('>');
        writeDone->P();
      } else {
#endif // CHANGED
        console->PutChar (ch);  // echo it!
        writeDone->P ();    // wait for write to finish
#ifdef CHANGED


      }
      if (ch == EOF)  
          break;
#endif // CHANGED
      if (ch == 'q')
          break;        // if q, quit
      }
    delete console;
    delete readAvail;
    delete writeDone;
}


#ifdef CHANGED
void
SynchConsoleTest (const char *in, const char *out) {
  bool overflow = false;
  int ch;
  char *str = (char*) malloc(sizeof(char*) * MAX_STRING_SIZE);
  int i = 0;
  SynchConsole *test_synchconsole = new SynchConsole(in, out);

  while ((ch = test_synchconsole->SynchGetChar()) != EOF) {
	  if(ch != '\n') {
	    if (!overflow) {
	      str[i] = ch;
	      i++;
	    }
	    if (i > MAX_STRING_SIZE) {
	      fprintf(stderr, "String too long, maximumm size allowed: %d\n", MAX_STRING_SIZE);
	      i = 0;	 
	      overflow = true;
	      free(str);
	      str = (char*) malloc(sizeof(char*) * MAX_STRING_SIZE);
	    }
	  }
	  else {	 
	    if (!overflow){
	      if (str[0] == '\n')
	        test_synchconsole->SynchPutString(str);
	      else {
	        str[i] = '\0';
	        test_synchconsole->SynchPutChar('<');
	        test_synchconsole->SynchPutString(str);
	        test_synchconsole->SynchPutString(">\n");
	        i = 0;
	      }
	    }
	    overflow = false;
	  }
  }
    
  fprintf(stderr, "EOF detected in SynchConsole!\n");
}

void
SynchConsoleTest2 (const char *in, const char *out)
{
  int n = 4;
  char *str = (char*) malloc(sizeof(char*) * n);
  SynchConsole *test_synchconsole = new SynchConsole(in, out);

  while (1) {
    test_synchconsole->SynchGetString(str, n);
    test_synchconsole->SynchPutString(str);
    free(str);
    str = (char*) malloc(sizeof(char*) * n);
  }
    
  fprintf(stderr, "EOF detected in SynchConsole!\n");
}



#endif // CHANGED
